package com.zwh.se.method;

/**
 * @author yexi
 *
 * 方法(method)就是一段用来完成特定功能的代码片段，类似于其它语言的函数(function)。
 * 方法用于定义该类或该类的实例的行为特征和功能实现。方法是类和对象行为特征的抽象。
 * 方法类似于面向过程中的函数。面向过程中，函数是最基本单位，整个程序由一个个函数调用组成。
 * 面向对象中，整个程序的基本单位是类，方法是从属于类和对象的。
 *
 * 方法的作用：是为了提高代码的复用性
 * 它并不是一个死概念，它的实际使用只跟你的实际使用场景有关
 */
public class Method_Info {

    // 方法声明格式：[修饰符1  修饰符2  …]  返回值类型   方法名(形式参数列表){ 方法体; return 方法返回值; }


    // 其中 int 为本方法会返回的数据类型，俗称"返回值类型"。如无返回值，必须显示指定为void。
    // ()内的参数表示要调用这个方法必须传入的参数(要传几个,要传什么类型)，称为"形式参数"(形参)
    // 形参由于在本方法内才被定义，所以它们的作用域也只在这方法内，出了方法体就没了
    public static int add(int num1, int num2) {
        int r = num1 + num2;
        return r;
        // return的作用： return 会直接结束当前它所处的方法并且不再执行。此时如果有返回值，则带着返回的值交给调用者
        // return 后面的值称之为"返回值"，代表着方法在执行完毕后会带着这个值交给调用者，并且"返回值"需要与"返回值类型"相同
    }

    // void 代表该方法不需要返回值(不需要通过return返回一个具体值,可以省略不写),也意味着使用这个方法就会直接运行逻辑,而不会获取到一个返回值
    static void print(Object o) {
        if ((int) o != 300) {
            //虽然 void 不需要返回值,但这里是测试 return 的直接结束方法调用逻辑，这将导致下方的正确判断没法进行
            return;
        }
        if (o instanceof Integer) {
            System.out.println("这一部分由于return已经结束了方法，所以是不会被调用的");
        }
    }


    //在同一类中,具有相同的方法名但参数列表不同的多个方法构成方法重载(overload)
    //判断标准: 1.同一类中 2.相同的方法名 3.形式参数列表不同(个数,顺序,类型,满足其中一个即可)
    //PS:方法重载与返回值、方法修饰符无关
    //方法签名:方法名称 + 方法参数列表，在同一个类中，方法签名是唯一的，否则编译报错

    //方法重载的作用：同一功能的方法通过传入不同的参数可以获得不一样的流程和结果
    //  注意的是，重载的方法，对于计算机而言，它实际就是完全不同的方法，只是对于人类而言，它的名称相同而已！

    //当方法需要传入的多个值为同一类型时，可以考虑使用"可变参数"
    //可变参数是在JDK1.5之后加入的新特性
    //PS:可变参数一定要作为方法的最后一个参数，否则会报错
    //PS:可变参数由于参数可变的原因,因此成功触发了方法重载
    public static int add(int... num) {
        //可变参数在传入方法时,在方法内作为一个数组使用
        int[] numArr = num;
        int nums = 0;
        for (int i : numArr) {
            nums += i;
        }
        return nums;
    }

    //参照物
    public static Object add(Object o) {
        return o;
    }

    //方法可以进行嵌套，那方法是否可以自己调用自己呢？答案是可以的。
    //我们把方法自身调用自身的现象称为"递归"，实现递归的方法又叫"递归函数"。
    //虽然方法自身可以调用自身,但要使得递归停止需要有两个要素:[1]递归停止的条件 [2]递归体(方法体)，否则递归不停止持续运行将会造成内存溢出
    //递归的使用场景和问题特征:当解决一个问题,可以分为多层步骤,而外层解决问题的步骤和内层解决问题的步骤一样时
    //外层问题依赖内层问题的解决,内层问题解决了,外层问题自然解决

    //比如下面这个经典的求数的阶乘
    public static long fact(int n) {
        //递归结束条件
        if (1 == n) {
            return 1;
        }
        //在idea中，使用递归时会出现左边那个符号，认住出现这个符号就是递归的意思
        return n * fact(n - 1);
    }
    // 递归的好处和坏处:
    // 好处：让程序简单明了,好理解
    // 坏处：递归由于不断自己不断调用自己,递归不结束,内存就一直被占用,加大资源的消耗,且如果递归的层次比较深,会造成栈溢出。

    public static void main(String[] args) {
        //方法的调用方式:传入实参(调用方法时实际传给方法的常量或变量),传递到方法那边转变为那边的形式参数(形参)
        int result = add(10, 20);
        System.out.println("结果 = " + result);

        //方法之间也是可以嵌套调用的
        print(add(101, 200));

        //测试方法重载
        System.out.println("结果 = " + add(123, 43, 34));

        //测试递归
        long fact = fact(5);
        System.out.println(fact);

        //特殊情况：只会在demo的使用中出现
        // 当重载时同时存在着数组和对象的单参传入时,不显式指定null的对象的话,则默认调用形参为数组的重载方法
        try {
            add(null);
        } catch (Exception e) {
            System.out.println("\033[31;4m" + e + "\033[0m");
        }
        // 显式指定的时候才会正常调用
        System.out.println(add((Object) null));
    }
}
